`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2024/11/06 08:30:22
// Design Name: 
// Module Name: counter_top_2class
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

`include "counter_def_class2.vh"
module counter_top_2class(
    input           clk,
    input           rst,
    input           c_rst,
    input           c_stop,
    input [1:0]     c_dir, //1向上，0向下
    input [`CNT_WIDTH-1:0]     c_crr,
    output      reg pwm
 );
    
 reg [`CNT_WIDTH-1:0]  cnt;
 reg        dir;
 reg [1:0]  curr_state;
 reg [1:0]  nxt_state;
 wire       clk_cnt; 
 wire       rst_cnt;
 
 parameter CNT_STATE  = 0;
 parameter RST_STATE  = 1;
 parameter STOP_STATE = 2;
 //----------------------------------------------------------------
 // CRM模块：计数器的时钟和复位生成
 //----------------------------------------------------------------
 crm_3class u_crm_3class(
    .clk        (clk    ),
    .rst        (rst    ),
    .clk_cnt    (clk_cnt),
    .rst_cnt    (rst_cnt)
);
 //----------------------------------------------------------------
 // CNT模块：计数器的主要逻辑
 //----------------------------------------------------------------
 always@(posedge clk_cnt or negedge rst_cnt)begin
    if(!rst_cnt)begin
        cnt<={`CNT_WIDTH{1'b0}};
    end
    else begin
        case(curr_state)
            CNT_STATE:begin
                if(dir) cnt<=cnt+1'b1;
                else if(!dir) cnt<=cnt-1'b1;
            end
            RST_STATE:begin
               cnt<=0;
            end
            STOP_STATE:begin
                cnt<=cnt;
            end
            default:begin
                 cnt<=cnt;
            end
        endcase
    end
 end   
 //----------------------------------------------------------------
 // DIR模块：决定计数器模块的计数方向
 //----------------------------------------------------------------
 always @(posedge clk_cnt or negedge rst_cnt)begin
    if(!rst_cnt)begin
        dir<=0;
    end
    else if(c_dir==0)begin
        dir<=0;
    end
    else if(c_dir==1)begin
        dir<=1;
    end
    else if(c_dir==2)begin
        if(dir==1 && cnt=={`CNT_WIDTH{1'b1}}-1)begin
            dir<=0;
        end
        else if(dir==0 && cnt=={`CNT_WIDTH{1'b0}}+1)begin
            dir<=1;
        end
        else begin
            dir<=dir;
        end
    end
 end   
 
 //----------------------------------------------------------------
 // 状态机：
 //----------------------------------------------------------------
    always@(posedge clk_cnt or negedge rst_cnt)begin
        if(!rst_cnt)begin
            curr_state  <=  CNT_STATE;
        end
        else begin
            curr_state  <=  nxt_state;
        end
    end
     
    always @(c_rst or c_stop)begin
        case(curr_state)
            CNT_STATE:begin
                if(!c_rst)begin
                    nxt_state = RST_STATE;
                end
                else if(c_stop)begin
                    nxt_state = STOP_STATE;
                end
                else begin
                    nxt_state = CNT_STATE;
                end
            end
            RST_STATE:begin
                if(!c_rst)begin
                    nxt_state = RST_STATE;
                end
                else if(c_stop)begin
                    nxt_state = STOP_STATE;
                end
                else begin
                    nxt_state = CNT_STATE;
                end
            end
            STOP_STATE:begin
                if(!c_rst)begin
                    nxt_state = RST_STATE;
                end
                else if(c_stop)begin
                    nxt_state = STOP_STATE;
                end
                else begin
                    nxt_state = CNT_STATE;
                end
            end
            default:begin
                 nxt_state = CNT_STATE;
            end
        endcase
    end
    
 //----------------------------------------------------------------
 // 输出比较模块：
 //----------------------------------------------------------------

   always@(posedge clk_cnt or negedge rst_cnt)begin
        if(!rst_cnt)begin
            pwm  <=  0;
        end
        else if( curr_state==CNT_STATE && cnt<=c_crr )begin
            pwm  <=  0;
        end
        else if( curr_state==CNT_STATE && cnt>c_crr )begin
            pwm  <=  1;
        end        
        else begin
            pwm  <=  0;
        end
    end

    
endmodule

